struct ColoredString {
    input: String,//输入的原始字符串
    fgcolor: String,//前景色
    bgcolor: String,//后景色
}

trait Colorize {
    //这个trait 包含了FG_RED, BG_YELLOW 两个常量，　叫做关联常量。
    //和关联类型类似由实现该trait的类型来指定常量的值。
    const FG_RED : &'static str = "31";
    const BG_YELLOW : &'static str = "43";
    fn red(self) -> ColoredString;
    fn on_yellow(self) -> ColoredString;
}
//实现默认构造函数
impl Default for ColoredString {
    fn default() -> Self {
        ColoredString {
            input: String::default(),
            fgcolor: String::default(),
            bgcolor: String::default(),
        }
    }
}

impl<'a> Colorize for ColoredString {
    fn red(self) -> ColoredString {
        ColoredString {
            fgcolor: String::from(ColoredString::FG_RED), ..self //更新语法 ..self
        }
    }

    fn on_yellow(self) -> ColoredString {
        ColoredString{
            bgcolor: String::from(ColoredString::BG_YELLOW), ..self 
        }
    }
}

impl<'a> Colorize for &'a str {
    fn red(self) -> ColoredString {
        ColoredString{
            fgcolor: String::from(ColoredString::FG_RED),
            input: String::from(self),
            ..ColoredString::default() // 更新语法 ..ColoredString::default()
        }
    }

    fn on_yellow(self) -> ColoredString{
        ColoredString{
            bgcolor: String::from(ColoredString::BG_YELLOW),
            input: String::from(self),
            ..ColoredString::default()
        }
    }
}

impl ColoredString {
    fn compute_style(&self) -> String { //使用compute_stype组装ANSI序列的前半部分 \x1B[31;43m
        // 前半部分使用\x1B定义ANSI序列的开始
        // 颜色编码31;43 , 31表示红背景色，43表示黄背景色, 分号分隔
        // 结束符m代表颜色控制符已经设置完毕
        let mut res = String::from("\x1B[");
        let mut has_bgcolor = false;

        if !self.bgcolor.is_empty() { // is_empty() 是String类类型中的方法，字符创为空返回true
            res.push_str(&self.bgcolor);// push_str() 参数需要&str类型，这里使用了&self.bgcolor，&String 可以自动解引用为&str
            has_bgcolor = true;
        }

        if !self.fgcolor.is_empty() {
            if has_bgcolor { res.push(';'); }
            res.push_str(&self.fgcolor);
        }
        res.push('m');
        res
    }
}

use std::fmt;

impl fmt::Display for ColoredString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 
        // fmt::Formatter 类型是一个结构体，专门用于提供记录格式化相关的信息
        // 提供了write_str，用于将指定的数据结构记录到底层的缓冲区中。
        // fmt 方法返回fmt::Result 类型
        // try!  是标准库中提供的专门用于错误处理的宏，如果出现错误，会自动返回相应的Err.
        let input = &self.input.clone();
        (f.write_str(&self.compute_style()))?;
        (f.write_str(input))?;
        (f.write_str("\x1B[0m"))?;
        Ok(())//返回Ok(()) 表示正常结束
    }
}

// Display 是定义于std::fmt的trait，它和Debug很相似。
// Debug 专门用于格式化打印的trait,通过{:?}来格式化打印指定输出，
// ?代表Debug模式
// Debug可以通过#[derive(Debug)] 属性来自动派生。
// Display 是通过{} 来格式化打印的，比Debug适用的范围更广，
// 更常用于手工实现非自动派生
//
//
fn main() {
    let hi = "Hello".red().on_yellow();
    println!("{}", hi);
    let hi = "Hello".on_yellow();
    println!("{}", hi);
    let hi = "Hello".red();
    println!("{}", hi);
    let hi = "Hello".on_yellow().red();
    println!("{}", hi);
}
